﻿using System;
using System.Reflection;
using NSubstitute;
using Phoenix.Exceptions;
using Phoenix.Framework;
using Phoenix.Tests.Views;
using Xunit;

namespace Phoenix.Tests.Framework
{
    public class DefaultViewLocatorTests
    {
        readonly DefaultViewLocator defaultLocator;
        readonly IAssemblyTypeProvider assemblyTypeProvider;

        public DefaultViewLocatorTests()
        {
            assemblyTypeProvider = Substitute.For<IAssemblyTypeProvider>();
            defaultLocator = new DefaultViewLocator(assemblyTypeProvider);
            defaultLocator.AddAssemblyToScan(GetType().Assembly);
        }

        [Fact]
        public void locate_view_finds_single_view_in_views_folder()
        {
            // arrange
            var matchingType = typeof(ExampleView);
            var nonMatchingType = Substitute.For<Type>();
            nonMatchingType.FullName.Returns("TestProj.Services.MyService");
            nonMatchingType.Namespace.Returns("TestProj.Services");
            assemblyTypeProvider
                .GetTypes(Arg.Any<Assembly>())
                .Returns(new[] { nonMatchingType, matchingType });

            // act
            var view = defaultLocator.Locate(new ControllerAction("TestController", "Example", null));

            // assert
            Assert.IsType<ExampleView>(view);
        }

        [Fact]
        public void locate_view_throws_view_not_found_exception_when_no_views_matching_are_found()
        {
            // arrange
            var nonMatchingType = Substitute.For<Type>();
            nonMatchingType.FullName.Returns("TestProj.Services.MyService");
            nonMatchingType.Namespace.Returns("TestProj.Services");
            assemblyTypeProvider
                .GetTypes(Arg.Any<Assembly>())
                .Returns(new[] { nonMatchingType });

            // act / assert
            Assert.Throws<ViewNotFoundException>(() => defaultLocator.Locate(new ControllerAction("TestController", "Example", null)));
        }

        [Fact]
        public void locate_view_throws_ambiguous_exception_when_no_multiple_matching_views_are_found()
        {
            // arrange
            var matchingType = typeof(ExampleView);
            assemblyTypeProvider
                .GetTypes(Arg.Any<Assembly>())
                .Returns(new[] { matchingType, matchingType });

            // act / assert
            Assert.Throws<AmbiguousMatchException>(() => defaultLocator.Locate(new ControllerAction("TestController", "Example", null)));
        }
    }
}